﻿//StrategyStorageMonitor.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Storages
{
	using System;
	using System.Collections.Generic;

	using Ecng.Common;
	using Ecng.Collections;

	using StockSharp.Algo.Strategies;
	using StockSharp.BusinessEntities;

	/// <summary>
	/// Специальный класс, сохраняющий данные из стратегий <see cref="Strategies"/> во внешнее хранилище.
	/// </summary>
	public class StrategyStorageMonitor : Disposable
	{
		private sealed class StrategyList : BaseList<Strategy>
		{
			private sealed class StrategyWrapper : Disposable
			{
				private readonly Strategy _strategy;
				private readonly StrategyInfo _info;

				public StrategyWrapper(Strategy strategy, StrategyInfo info)
				{
					if (strategy == null)
						throw new ArgumentNullException("strategy");

					if (info == null)
						throw new ArgumentNullException("info");

					strategy.NewOrder += OnNewOrder;
					strategy.OrderChanged += OnOrderChanged;
					strategy.OrderFailed += OnOrderFailed;
					strategy.NewStopOrder += OnNewOrder;
					strategy.StopOrderChanged += OnOrderChanged;
					strategy.StopOrderFailed += OnOrderFailed;
					strategy.NewMyTrades += OnNewMyTrades;

					_strategy = strategy;
					_info = info;
				}

				private void OnNewOrder(Order order)
				{
					_info.Orders.Save(order);
				}

				private void OnOrderChanged(Order order)
				{
					_info.Orders.Save(order);
				}

				private void OnOrderFailed(OrderFail fail)
				{
					_info.OrderFails.Save(fail);
				}

				private void OnNewMyTrades(IEnumerable<MyTrade> trades)
				{
					trades.ForEach(t => _info.MyTrades.Save(t));
				}

				protected override void DisposeManaged()
				{
					_strategy.NewOrder -= OnNewOrder;
					_strategy.OrderChanged -= OnOrderChanged;
					_strategy.OrderFailed -= OnOrderFailed;
					_strategy.NewStopOrder -= OnNewOrder;
					_strategy.StopOrderChanged -= OnOrderChanged;
					_strategy.StopOrderFailed -= OnOrderFailed;
					_strategy.NewOrder -= OnNewOrder;

					base.DisposeManaged();
				}
			}

			private readonly Dictionary<Strategy, StrategyWrapper> _wrappers = new Dictionary<Strategy, StrategyWrapper>();
			private readonly StrategyStorageMonitor _monitor;

			public StrategyList(StrategyStorageMonitor monitor)
			{
				if (monitor == null)
					throw new ArgumentNullException("monitor");

				_monitor = monitor;
			}

			protected override bool OnAdding(Strategy item)
			{
				var info = _monitor.StorageRegistry.Strategies.LoadByStrategyId(item.Id);

				if (info == null)
				{
					info = new StrategyInfo
					{
						Id = item.Id,
						Name = item.Name,
						Settings = new Dictionary<string, string>(),
					};

					_monitor.StorageRegistry.Strategies.Add(info);
				}

				_wrappers.Add(item, new StrategyWrapper(item, info));
				return base.OnAdding(item);
			}

			protected override bool OnRemoving(Strategy item)
			{
				var wrapper = _wrappers.TryGetValue(item);

				if (wrapper != null)
				{
					_wrappers.Remove(item);
					wrapper.Dispose();
				}

				return base.OnRemoving(item);
			}
		}

		/// <summary>
		/// Создать <see cref="StrategyStorageMonitor"/>.
		/// </summary>
		/// <param name="storageRegistry">Интерфейс, описывающий внешнее хранилище.</param>
		public StrategyStorageMonitor(IStorageRegistry storageRegistry)
		{
			if (storageRegistry == null)
				throw new ArgumentNullException("storageRegistry");

			StorageRegistry = storageRegistry;
			Strategies = new StrategyList(this);
		}

		/// <summary>
		/// Интерфейс, описывающий внешнее хранилище.
		/// </summary>
		public IStorageRegistry StorageRegistry { get; private set; }

		/// <summary>
		/// Стратегии, данные которых необходимо сохранять.
		/// </summary>
		public ICollection<Strategy> Strategies { get; private set; }

		///// <summary>
		///// Сохранить информацию по заявке.
		///// </summary>
		///// <param name="strategy">Стратегия, которой принадлежит заявка.</param>
		///// <param name="order">Заявка, информацию которой необходимо сохранить.</param>
		//protected virtual void SaveOrder(Strategy strategy, Order order)
		//{
		//    GetStrategy(strategy).Orders.Save(order);
		//}

		///// <summary>
		///// Сохранить информацию по моей сделке.
		///// </summary>
		///// <param name="strategy">Стратегия, которой принадлежит сделка.</param>
		///// <param name="trade">Моя сделка, информацию которой необходимо сохранить.</param>
		//protected virtual void SaveMyTrade(Strategy strategy, MyTrade trade)
		//{
		//    GetStrategy(strategy).MyTrades.Save(trade);
		//}

		///// <summary>
		///// Сохранить информацию об ошибке регистрации заявки.
		///// </summary>
		///// <param name="strategy">Стратегия, которой принадлежит заявка.</param>
		///// <param name="fail">Описание ошибки, которая произошла при регистрации заявки.</param>
		//protected virtual void SaveRegisterOrderFail(Strategy strategy, OrderFail fail)
		//{
		//    GetStrategy(strategy).OrderRegisterFails.Save(fail);
		//}

		/// <summary>
		/// Освободить занятые ресурсы.
		/// </summary>
		protected override void DisposeManaged()
		{
			Strategies.Clear();
			base.DisposeManaged();
		}
	}
}
